/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <cmsis_os2.h>
//#include "softbus_server_frame.h"
//#include "auth_interface.h"
#include "bus_center_manager.h"
//#include "lnn_bus_center_ipc.h"
//#include "message_handler.h"
//#include "softbus_conn_interface.h"
//#include "softbus_disc_server.h"
#include "softbus_errcode.h"
//#include "softbus_feature_config.h"
//#include "softbus_log.h"
//#include "softbus_utils.h"
//#include "trans_session_manager.h"
#include "trans_session_service.h"
#include "discovery_service.h"
#include "session.h"
#include "iot_wifi.h"

#define CONFIG_TASK_MAIN_PRIOR 25

#include <pthread.h>
#include "ohos_init.h"

extern void testThread(void(*test) (void *arg));
extern void hi_wifi_set_macaddr(char *mac, int len);

char g_networkId[99] = {0};
ISessionListener *g_sessionListener = NULL;
int32_t g_sessionId = -1;
SessionAttribute *g_sessionAttr = NULL;

#define PKGDEMO "discovery_demo_zyh"
#define SESSIONDEMO "zyh_test_softbus_1_27"

typedef enum {
    TRANS_STATE_NONE,
    TRANS_STATE_INIT,
    TRANS_STATE_JOIN,
    TRANS_STATE_OPEN,
    TRANS_STATE_SENDBYTE,
    TRANS_STATE_SENDMSG,
    TRANS_STATE_CLOSE,
    TRANS_STATE_LEAVE_LNN,
    TRANS_STATE_DUMP_MEM,
}TransState;

int g_state = TRANS_STATE_NONE;

int TestOnSessionOpened(int sessionId, int result) {
    g_sessionId = sessionId;
    printf("TestOnSessionOpened %d, %d \r\n", g_sessionId, result);
    return 0;
}

int TestOnSessionClosed(int sessionId, int result) {
    
    printf("TestOnSessionClosed\n");
    
    if (g_sessionId == sessionId) {
        g_sessionId = -1;
    }

    return 0;
}

void TestOnBytesReceived(int sessionId, const void *data, unsigned int dataLen) {

    printf("BytesReceived :data  %s, len: %d \r\n", data, dataLen);
  
}

void TestOnMessageReceived(int sessionId, const void *data, unsigned int dataLen) {

    printf("MessageReceived :data  %s, len: %d \r\n", data, dataLen);
}

int32_t TestSessionListenerInit(void) {
    if (g_sessionListener != NULL) {
        return SOFTBUS_OK;
    }

    g_sessionListener = (ISessionListener *)malloc(sizeof(ISessionListener));
    (void)memset(g_sessionListener, 0, sizeof(ISessionListener));
    g_sessionListener->OnSessionOpened = TestOnSessionOpened;
    g_sessionListener->OnSessionClosed = TestOnSessionClosed;
    g_sessionListener->OnBytesReceived = TestOnBytesReceived;
    g_sessionListener->OnMessageReceived = TestOnMessageReceived;

    g_sessionAttr = (SessionAttribute *)malloc(sizeof(SessionAttribute));
    g_sessionAttr->dataType = TYPE_MESSAGE;
    
    int ret = CreateSessionServer(PKGDEMO, SESSIONDEMO, g_sessionListener);
    printf("CerateSessionServer ret %d\r\n", ret);
    if (ret != SOFTBUS_OK) {
        return SOFTBUS_ERR;
    }
    return SOFTBUS_OK;
}

void onNodeOnline(NodeBasicInfo *info) {
    printf("noNodeline \n");
    strcpy(g_networkId, info->networkId);
    printf("networkId:%s", g_networkId);
    g_state = TRANS_STATE_OPEN;
}

void onNodeOffline(NodeBasicInfo *info) {
    printf("onNodeOffline\n");
}

static INodeStateCb g_nodeStateCallBack = {
    .events = EVENT_NODE_STATE_ONLINE | EVENT_NODE_STATE_OFFLINE,
    .onNodeOnline = onNodeOnline,
    .onNodeOffline = onNodeOffline,
};

void regDevStatus(void) {
    printf("begin regDevStatus\r\n");
    int ret = RegNodeDeviceStateCb(PKGDEMO, &g_nodeStateCallBack);
    printf("end regDevStatus\r\n");
}


static SubscribeInfo g_sInfo = {
    .subscribeId = 1,
    .mode = DISCOVER_MODE_ACTIVE,
    .medium = COAP,
    .freq = MID,
    .capability = "ddmpCapability",
    .capabilityData = NULL,
    .dataLen = 0,
    .isSameAccount = true,
    .isWakeRemote = false
};

static void OnDeviceFound(const DeviceInfo *device)
{
    if (device == NULL) {
        printf("ondevice found device is null\n");
        return;
    }
    printf("***********OnDeviceFound!!!!!******************************************\n");
    printf("id : %s.\n", device->devId);
    printf("name : %s.\n", device->devName);
    printf("device type : %u.\n", device->devType);
    printf("capNum : %u.\n", device->capabilityBitmapNum);
    for (uint32_t i = 0; i < device->capabilityBitmapNum; i++) {
        printf("capBitmap[%u] : %u.\n", i, device->capabilityBitmap[i]);
    }
    printf("addr num : %u.\n", device->addrNum);
    printf("ip : %s.\n", device->addr[0].info.ip.ip);
    printf("port : %d.\n", device->addr[0].info.ip.port);
    printf("connect type : %d.\n", device->addr[0].type);
    printf("peerUid : %s.\n", device->addr[0].peerUid);
    printf("hw account hash : %s.\n", device->accountHash);
    printf("**********************************************************************\n");
    return;
}

static void TestDeviceFound(const DeviceInfo *device)
{
    printf("[client]TestDeviceFound\n");
    OnDeviceFound(device);
}

static void TestDiscoverFailed(int subscribeId, DiscoveryFailReason failReason)
{
    printf("[client]TestDiscoverFailed, subscribeId = %d, failReason = %d\n", subscribeId, failReason);
}

static void TestDiscoverySuccess(int subscribeId)
{
    printf("[client]TestDiscoverySuccess, subscribeId = %d\n", subscribeId);
}

static IDiscoveryCallback g_subscribeCb = {
    .OnDeviceFound = TestDeviceFound,
    .OnDiscoverFailed = TestDiscoverFailed,
    .OnDiscoverySuccess = TestDiscoverySuccess
};


void closeLoopSession(int *sid, int loopcnt) {
    printf("closeLoopSession %d \r\n", loopcnt);

    for (int i = 0; i < loopcnt; i++) {
        printf("closeLoopSession id %d\n", sid[i]);
        CloseSession(sid[i]);
        sleep(1); 
    }
}

void loopOpenSessionTask() {
    char groupId[128] = {0};
    int loopcnt = 10;
    int totalLoop = loopcnt;
    static int sendcnt = 1;
    int ret = 0;
    char data[20] = "zyh send byte data";
    
    int *sid = calloc(1, sizeof(int) * loopcnt);
    sleep(10);

    printf("Start loopOpenSessionTask\n");

    while (loopcnt != 0) {
        sprintf(groupId, "groupid:%d", rand());

        sid[loopcnt -1 ] = OpenSession(SESSIONDEMO, SESSIONDEMO, g_networkId, groupId, g_sessionAttr);

        sleep(1);

        for (int i = 0; i < sendcnt; i++) {
            printf("Test No[%d]\n", i+1);

            ret = SendMessage(g_sessionId, data, sizeof(data));
            if (ret != 0) {
                printf("SendMessage failed ret = %d\n", ret);
                break;
            }

            sleep(1);

            ret = SendBytes(g_sessionId, data, sizeof(data));
            if (ret != 0) {
                printf("SendBytes failed ret = %d\n", ret);
                break;
            }
            sleep(1);
        }
        sleep(1);
        loopcnt--;
    
    }
    sleep(2);
    closeLoopSession(sid, totalLoop);
    free(sid);
    return;
}

static void OnleaveLNNDone(const char *networkID, int32_t retCode) {
    printf("OnleaveLNNDone ret:%d\n", retCode);
    g_state = TRANS_STATE_DUMP_MEM;
}

void stateProc(int state) {
    int ret;
    char data[] = "zyh L0 session send message data";
    char databyte[] = "zyh L0 session send byte data";
    char groupid[128] = {0};

    static int cnt = 0;
    printf("state:%d\n", state);
    switch (state) {
        case TRANS_STATE_INIT: {
            sleep(1);
            break;
        }
        case TRANS_STATE_JOIN: {
            break;
        }
        case TRANS_STATE_OPEN: {
            loopOpenSessionTask();
            break;
        }
        case TRANS_STATE_SENDBYTE: {
            ret = SendBytes(g_sessionId, data, sizeof(data));
            if (ret != SOFTBUS_OK) {
                printf("SendByte ret:%d\n", ret);
            }
            break;
        }
        case TRANS_STATE_SENDMSG: {
            ret = SendMessage(g_sessionId, data, sizeof(data));
            if (ret != SOFTBUS_OK) {
                printf("SendMessage ret:%d\n", ret);
            }
            break;
        }
        case TRANS_STATE_CLOSE: {
            CloseSession(g_sessionId);
            g_sessionId = -1;
            break;
        }
        case TRANS_STATE_LEAVE_LNN: {
            sleep(1);
            g_sessionId = -1;
            break;
        }
        case TRANS_STATE_DUMP_MEM: {
            sleep(5);
            break;
        }
        default : {
            sleep(5);
            break;
        }
    }
}

void StateProcTask() {
    int tmpState;

    while (1) {
        if (g_state != TRANS_STATE_NONE) {
            tmpState = g_state;
            g_state = TRANS_STATE_NONE;
            stateProc(tmpState);
        }
        sleep(1);
    }
}

void SoftbusTestTask(void *arg) {
    
    if (BOARD_ConnectWifi("zhangyuhang", "12345678") != 0) {
        printf("Connect wifi failed \n");
        return;
    }

    printf("Sleep 20 , enter the softbus test task\n");

    InitSoftBusServer();

    printf("begain startDiscovery\n");
    
    int testCount = 0;
    int maxTestCount = 5;
    while (testCount < maxTestCount) {
        StartDiscovery(PKGDEMO, &g_sInfo, &g_subscribeCb);
        testCount++;
    }
    printf("begin regDevStatus\n");

    regDevStatus();
    TestSessionListenerInit();
    
    printf("proc state \n");
    StateProcTask();
}

void SoftbusDiscoveryTestEntry() {
    printf("Start SoftbusTestEntry \n");
    char mac[6] = {0x8c, 0x22, 0x33, 0x44, 0x55, 0x44};
    hi_wifi_set_macaddr(mac, sizeof(mac));
    osThreadAttr_t attr;
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 8096;
    attr.priority = CONFIG_TASK_MAIN_PRIOR;

    attr.name = "SoftbusTest";
    (void) osThreadNew((osThreadFunc_t)SoftbusTestTask, NULL, (const osThreadAttr_t *)&attr);

    return;
}

APP_FEATURE_INIT(SoftbusDiscoveryTestEntry);
